import err from './error.js'
import remote from './remote.js'
import {
	CacheSet,
	CacheMap
} from './cache.js'



// service object
class User{
	constructor() {
		//cache with remote state 只缓存远端的最原始数据，其他的属性临时拼上去
		this._ucache = new CacheMap('prayUserInfo')
	}
	async getSms(phone, captcha){
		await remote.userLoginSendSms({
			phone:phone,
			ticket: captcha.ticket,
			nonce: captcha.randstr
		})
	}
	async login(phone, code){
		let user = await remote.userLogin({
			phone:phone,
			code: code
		})
		if(user.starImages){
			this._ucache.set('id', user.id);
			await (new CrystalImage()).syncMyStarList(user.starImages);
			return true
		}else return false
	}
	getId(){
		if(this._ucache.has('id')) return this._ucache.get('id')
		else return false
	}
	async getInfo(){
		return await remote.userInfo()
	}
	offLine(){
		this._ucache.remove('id')
	}
	logout(){
		remote.userLogout();
		this._ucache.clear();
		(new CrystalImage()).clearCache();
		(new Package()).clearCache()
	}
}

const U = new User()

class CrystalImage {
	constructor() {
		//cache with remote state 只缓存远端的最原始数据，其他的属性临时拼上去
		this._icache = new CacheMap('huazangImages')
		this._scache = new CacheSet('huazangImagesMyStar')
		//cache without remote state (local only)
		this._vcache = new CacheSet('huazangImagesMyUpvote')
		this._ccache = new CacheSet('huazangImagesMyUpvoteComments')
	}
	clearCache(){
		this._icache.clear()
		this._scache.clear()
		this._vcache.clear()
		this._ccache.clear()
	}
	_has(imgId) {
		if (this._icache.get(imgId)) return true
		else return false
	}
	_chkVote(img) {
		img.upvote = parseInt(img.zan)
		return img
	}
	_chkMyVote(img) {
		if (this._vcache.initDone()) {
			img.myUpvote = this._vcache.has(img.id)
		} else {
			img.myUpvote = false
		}
		if(img.myUpvote) img.upvote++
		return img
	}
	async _chkMyStar(img) {
		img.myStar = this._scache.has(img.id)
		return img
	}
	async _d(img) { // decorate attributes
		return await this._chkMyStar(this._chkMyVote(img))
	}
	
	async getIdList(){
		let idListObj = this._icache.get('imgIdList')
		let now = Date.now()
		if(idListObj && now-idListObj.cacheTime<86400000) return idListObj.data
		else{
			let data = await remote.getImgIdList()
			this._icache.set('imgIdList',{cacheTime:now, data:data})
			return data
		}
	}
	
	async get(imgId) {
		let img = this._icache.get(imgId)
		if (!img) {
			img = this._chkVote((await remote.getImgDetailList([imgId]))[0])
			this._icache.set(img.id, img)
		}
		return await this._d(img)
	}

	async getList(imgIdList) {
		let idToQuery = []
		for (let id of imgIdList) {
			if (!this._icache.get(id)) idToQuery.push(id)
		}
		if (idToQuery.length > 0) {
			let res = (await remote.getImgDetailList(idToQuery))
			for (let img of res) {
				this._icache.set(img.id, this._chkVote(img))
			}
		}
		let result = []
		for (let id of imgIdList) {
			result.push(await this._d(this._icache.get(id)))
		}
		return result
	}

	upvote(imgId) { // return void
		this._vcache.add(imgId)
		remote.incImageUpvote(imgId) // async run
	}
	cancelUpvote(imgId) {
		this._vcache.rm(imgId)
	}
	async star(imgId) {
		this._scache.add(imgId)
		if(U.getId()) {
			let res = await remote.starImages([imgId])
			if(res=='not login') U.offLine()
		}
	}
	async cancelStar(imgId) {
		this._scache.rm(imgId)
		if(U.getId()) {
			let res = await remote.cancelStarImage(imgId)
			if(res=='not login') U.offLine()
		}
	}
	async syncMyStarList(remoteStarList){
		let local = this._scache.asArray()
		if(remoteStarList.length>0){
			let s = new Set(local)
			remoteStarList.forEach(id=>{s.add(id)})
			this._scache.setValues([...s])
		}
		if(local.length>0){
			remote.starImages(local)
		}
	}
	async getMyStarList() {
		return this._scache.asArray()
	}
	comment(imgId, nickName, content, fromPackage, captcha){
		remote.commentImage({
			imgid: imgId,
			name: nickName,
			content: content,
			fromPackage: fromPackage?fromPackage:'',
			ticket: captcha.ticket,
			nonce: captcha.randstr,
		})
	}
	async selectedComments(imgId, page){
		let comments = await remote.getImageComments({
			imgid: imgId,
			page: page?page:1
		})
		for (let c of comments){
			c.time=new Date(c.time)
			c.myvote = this._ccache.has(c.id)
			c.upvote = parseInt(c.upvote)
		}
		return comments
	}
	async recentComments(imgId, page){
		let comments = await remote.getImageComments({
			imgid: imgId,
			recent: 1,
			page: page?page:1
		})
		for (let c of comments){
			c.time=new Date(c.time)
			c.myvote = this._ccache.has(c.id)
			c.upvote = parseInt(c.upvote)
		}
		return comments
	}
	upvoteComment(commentId){
		this._ccache.add(commentId)
		remote.upvoteImageComment(commentId)
	}
	cancelUpvoteComment(commentId){
		this._ccache.rm(commentId)
	}
}

class Package {
	constructor() {
		//cache without remote state (local only)
		this._tcache = new CacheSet('prayPackageMyThank')
	}
	_extractGpsPoint(gpsPoint) {
		if (gpsPoint) return gpsPoint.coordinates
		else return null
	}
	_d(p) { // decorate attributes
		// console.log(p)
		p.myThank = this._tcache.has(p._id)
		if (p.sender.gps) p.sender.gps = this._extractGpsPoint(p.sender.gps)
		if (p.target.gps) p.target.gps = this._extractGpsPoint(p.target.gps)
		return p
	}
	async add(p, captcha) {
		await remote.addPackage({p:p, captcha: captcha})
	}
	async getById(id) {
		let p = (await remote.getPackageById(id)).data
		if(p.data.length==1) return this._d(JSON.parse(p.data[0]))
		else throw 'pkg not found'
	}
	thank(id) {
		this._tcache.add(id)
		remote.incPackageThanks(id)
	}
	cancelThank(id) {
		this._tcache.rm(id)
	}
	async searchNearest(gps) {
		let p = JSON.parse((await remote.searchNearestPackage(gps)).resp_data)
		if (p) return this._d(p)
		else return p
	}
	async searchByRegion(region) {
		let p = JSON.parse((await remote.searchPackageByRegion(region)).resp_data)
		if (p) return this._d(p)
		else return p
	}
	clearCache(){
		this._tcache.clear()
	}
}



module.exports = {
	CrystalImage: CrystalImage,
	Package: Package,
	User: User,
}
